#ifdef RT_USE_OLD_CONN_WRAP

#include "RtBase.h"
#include "RtSessionOneForwardMany.h"
#include "RtThreadManager.h"
#include "RtMessageBlock.h"
#include "RtEventQueueBase.h"


CRtSessionOneForwardMany::CRtSessionOneForwardMany()
{
	m_pThreadNetwork = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_NETWORK);
	RT_ASSERTE(m_pThreadNetwork);
}

CRtSessionOneForwardMany::~CRtSessionOneForwardMany()
{
}

DWORD CRtSessionOneForwardMany::AddReference()
{
	return CRtReferenceControlMutilThread::AddReference();
}

DWORD CRtSessionOneForwardMany::ReleaseReference()
{
	return CRtReferenceControlMutilThread::ReleaseReference();
}

RtResult CRtSessionOneForwardMany::AddTransport(IRtTransport *aTrpt)
{
	RT_ASSERTE_RETURN(aTrpt, RT_ERROR_INVALID_ARG);

	CRtMutexGuardT<MutexType> theGuard(m_Mutex);
	m_Trpts.push_back(aTrpt);
	return RT_OK;
}

RtResult CRtSessionOneForwardMany::RemoveTransport(IRtTransport *aTrpt)
{
	RT_ASSERTE_RETURN(aTrpt, RT_ERROR_INVALID_ARG);

#if 0
	CRtConnectionManager::CType type = CRtConnectionManager::CTYPE_NONE;
	aTrpt->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, &type);
	RT_ASSERTE(RT_BIT_ENABLED(type, CRtConnectionManager::CTYPE_UDP));
#endif // 0

	CRtMutexGuardT<MutexType> theGuard(m_Mutex);
	TrptsType::iterator iter = std::find(
		m_Trpts.begin(), 
		m_Trpts.end(),
		aTrpt);
	if (iter != m_Trpts.end()) {
		m_Trpts.erase(iter);
		return RT_OK;
	}
	else
		return RT_ERROR_NOT_FOUND;
}

RtResult CRtSessionOneForwardMany::RemoveAllTransports()
{
	CRtMutexGuardT<MutexType> theGuard(m_Mutex);
	m_Trpts.clear();
	return RT_OK;
}

RtResult CRtSessionOneForwardMany::
SendDataToAll(CRtMessageBlock &aData, CRtTransportParameter *aPara, 
			  IRtTransport *aSender)
{
	DWORD dwTotal = aData.GetChainedLength();
	if (aPara)
		aPara->m_dwHaveSent = 0;

	RtResult rv;
	if (CRtThreadManager::IsEqualCurrentThread(m_pThreadNetwork->GetThreadId())) {
		Send_i(aData, aPara, aSender);
		rv = RT_OK;
	}
	else {
		CEventSendDataToAll *pEvent = new CEventSendDataToAll(
			this, aData, aPara, aSender);
		rv = m_pThreadNetwork->GetEventQueue()->PostEvent(pEvent);
	}

	if (RT_SUCCEEDED(rv)) {
		rv = aData.AdvanceChainedReadPtr(dwTotal);
		RT_ASSERTE(RT_SUCCEEDED(rv));
		if (aPara)
			aPara->m_dwHaveSent = dwTotal;
	}
	else {
		RT_ERROR_TRACE_THIS("CRtSessionOneForwardMany::SendDataToAll,"
			" PostEvent() failed!");
		RT_ASSERTE(rv != RT_ERROR_PARTIAL_DATA);
	}
	return rv;
}

RtResult CRtSessionOneForwardMany::
Send_i(CRtMessageBlock &aData, CRtTransportParameter *aPara, IRtTransport *aSender)
{
	DWORD dwSendSuccessful = 0;
	DWORD dwSendFailed = 0;
	DWORD dwSendSkip = 0;
	
#ifndef RT_DISABLE_EVENT_REPORT
	CRtTimeValue tvCur = CRtTimeValue::GetTimeOfDay();
#endif // !RT_DISABLE_EVENT_REPORT
	
	{
		CRtMutexGuardT<CRtSessionOneForwardMany::MutexType> theGuard(m_Mutex);

		//RT_ASSERTE(!aData.GetNext());
		//LPCSTR pStart = aData.GetTopLevelReadPtr();
		//DWORD dwLen = aData.GetTopLevelLength();
//		CRtString msg = aData.FlattenChained();
//		if(msg.empty())
//			return RT_OK;
//		DWORD dwLen = msg.length();
		aData.SaveChainedReadPtr();
		CRtSessionOneForwardMany::TrptsType::iterator iter = m_Trpts.begin();
		for ( ; iter != m_Trpts.end(); ++iter) {
			IRtTransport *pTrans = (*iter).Get();
			if (aSender == pTrans) {
				dwSendSkip++;
				continue;
			}

			// TODO: implement backward in CRtMessageBlock.
//			CRtMessageBlock mbCopy(
//				dwLen, 
//				const_cast<char*>(pStart), 
//				CRtMessageBlock::DONT_DELETE,
//				dwLen);
//			CRtMessageBlock mbCopy(
//				dwLen,
//				(char*)msg.c_str(),
//				CRtMessageBlock::DONT_DELETE,
//				dwLen);
			aData.RewindChained(TRUE);
			RtResult rv = pTrans->SendData(
				aData, 
				aPara);
			if (RT_FAILED(rv)) {
				// we do nothing if send failed.
				dwSendFailed++;
			}
			else {
				dwSendSuccessful++;
			}
		}
	}
	
#ifndef RT_DISABLE_EVENT_REPORT
	CRtTimeValue tvSub = CRtTimeValue::GetTimeOfDay() - tvCur;
	if (tvSub > CRtEventQueueBase::s_tvReportInterval) {
		RT_WARNING_TRACE_THIS("CEventSendDataToAll::OnEventFire, report,"
			" sec=" << tvSub.GetSec() << 
			" usec=" << tvSub.GetUsec() <<
			" dwSendSuccessful=" << dwSendSuccessful << 
			" dwSendFailed=" << dwSendFailed << 
			" dwSendSkip=" << dwSendSkip);
	}
#endif // !RT_DISABLE_EVENT_REPORT
	return RT_OK;
}

//////////////////////////////////////////////////////////////////////
// class CEventSendDataToAll
//////////////////////////////////////////////////////////////////////

CEventSendDataToAll::
CEventSendDataToAll(CRtSessionOneForwardMany *aSession, 
			   CRtMessageBlock &aData, 
			   CRtTransportParameter *aPara,
			   IRtTransport *aSender)
	: m_pOwnerSession(aSession)
	, m_pParaTransportParameter(NULL)
	, m_pTransportender(aSender)
{
	RT_ASSERTE(m_pOwnerSession);

	if (aPara) {
		m_TransportParameter = *aPara;
		m_pParaTransportParameter = &m_TransportParameter;
	}

	m_pMessageBlock = aData.DuplicateChained();
	RT_ASSERTE(m_pMessageBlock);
}

CEventSendDataToAll::~CEventSendDataToAll()
{
	if (m_pMessageBlock)
		m_pMessageBlock->DestroyChained();
}

RtResult CEventSendDataToAll::OnEventFire()
{
	RT_ASSERTE(CRtThreadManager::IsEqualCurrentThread(
		m_pOwnerSession->m_pThreadNetwork->GetThreadId()));

	if (m_pMessageBlock) {
		m_pOwnerSession->Send_i(
			*m_pMessageBlock, 
			m_pParaTransportParameter, 
			m_pTransportender.ParaIn());
	}
	return RT_OK;
}

#endif // RT_USE_OLD_CONN_WRAP
